/*
pararun: A program to run processes in parallel taking advantage of the number of processors.
    Copyright (C) 2011  Daniel Gutson

    This file is part of the Paragooas package.

    Pararun is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Pararun is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Pararun.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <set>

using namespace std;

class ParaProc
{
	const size_t proc_count;
	set<pid_t> running;
	static size_t getProcCount()
	{
		return sysconf(_SC_NPROCESSORS_ONLN);
	}

	void spawnProcess(const string& cmd)
	{
		pid_t pid;
		pid = fork();
		if ( pid == -1 )
			cerr << "Error while executing fork()" << endl;
		else if ( pid == 0 )
		{
			// child proc.
			int ret = system( cmd.c_str() );
			if ( ret != -1 )
				exit( WEXITSTATUS( ret ) );
			else
			{
				cerr << "Error while executing '" << cmd << "'" << endl;
				exit(1);
			}
		}
		else
		{
			// it's me (parent)
			running.insert( pid );
        	}
	}

	// wait for the completion of at least one child
	void waitCompletion()
	{
		int status;
		const pid_t proc = ::wait(&status);

		if (proc != -1)
		{
			const set<pid_t>::const_iterator it = running.find(proc);
			if (it != running.end())
			{
				running.erase(it);
			}
			else
				cerr << "Unknown pid " << proc << endl;
		}
		else
			cerr << "Error while calling wait()" << endl;
	}

public:
	ParaProc() : proc_count(getProcCount()) {}

	void runCmd(const string& cmd)
	{
		if (running.size() == proc_count)
			waitCompletion();

		spawnProcess(cmd);
	}

	void waitAll()
	{
		while (!running.empty())
			waitCompletion();
	}

	~ParaProc()
	{
		waitAll();
	}
};

int main()
{
	ParaProc proc;
	string line;
	while (getline(cin, line))
		proc.runCmd(line);

	return 0;
}

